﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using XapSpyAnalysis;
using Microsoft.Win32;
using System.IO;
using Microsoft.Research.DynamicDataDisplay; // Core functionality
using Microsoft.Research.DynamicDataDisplay.DataSources; // EnumerableDataSource
using Microsoft.Research.DynamicDataDisplay.PointMarkers; // CirclePointMarker

namespace XapSpyAnalysisWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private GraphicStatistic GraphicStatistic { get; set;}

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        }

        private void OpenMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // clear data from previous load
            clearData();
            // use selected file and load into memory
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.DefaultExt = ".txt";
            openFileDialog.ShowDialog();

            // check if the user did not hit cancel in openFileDialog
            if (!openFileDialog.FileName.Equals(""))
            {
                List<Data> dataList = loadFile(openFileDialog.FileName);
                Statistic statistic = new Statistic();
                statistic.DataList = dataList;
                statistic.NumberCalls = statistic.DataList.Count;
                statistic.calculateStatistic();
                statistic.countCalls();
                // refresh status toolbar
                StatusMessageLabel.Content = "Status: Data File " + openFileDialog.FileName + " loaded.";
                // refresh Label with new information from load
                NumberMethodsLabel.Content = NumberMethodsLabel.Content + statistic.NumberCalls.ToString();
                NumberUniqueMethodsLabel.Content = NumberUniqueMethodsLabel.Content + statistic.NumberUniqueMethods.ToString();
                statistic.convertCountDictionaryToList(statistic.CountCallsDictionary);
                refreshDataGrids(statistic);
                GraphicStatistic = new GraphicStatistic(statistic);
                plotStatistic(GraphicStatistic);  
            }
            else
            {
                // the user canceled the openFileDialog, do nothing
            }
            
        }

        /// <summary>
        /// Refreshes the DataGrids and connects them with their data sources.
        /// </summary>
        /// <param name="statistic"></param>
        private void refreshDataGrids(Statistic statistic)
        {
            // populate the GridView with entries from the Statistic object
            RawDataGrid.ItemsSource = statistic.DataList;
            MethodCountDataGrid.ItemsSource = statistic.CountCallsList;
        }

        /// <summary>
        /// Plots a graph like it is introduced here: http://msdn.microsoft.com/de-de/magazine/ff714591.aspx#MtViewDropDownText
        /// </summary>
        /// <param name="graphicStatistic"></param>
        private void plotStatistic(GraphicStatistic graphicStatistic)
        {
            var datesDataSource = new EnumerableDataSource<DateTime>(graphicStatistic.Dates);
            datesDataSource.SetXMapping(x => dateAxis.ConvertToDouble(x));

            var methodNamesDataSource = new EnumerableDataSource<int>(graphicStatistic.MethodNumbers);
            methodNamesDataSource.SetYMapping(y => y);
            methodNamesDataSource.AddMapping(ShapeElementPointMarker.ToolTipTextProperty,
                y => "Method: " + graphicStatistic.MethodHashDictionary[y]);

            CompositeDataSource compositeDataSource1 = new
              CompositeDataSource(datesDataSource, methodNamesDataSource);
            plotter.AddLineGraph(compositeDataSource1,
              new Pen(Brushes.Blue, 2),
              new CircleElementPointMarker
              {
                  Size = 10,
                  Brush = Brushes.Red,
                  Fill = Brushes.Orange
              },
              //new CirclePointMarker { Size = 10.0, Fill = Brushes.Red },
              new PenDescription("Method calls"));

            StringBuilder sb = new StringBuilder();
            // Loop over pairs with foreach
            foreach (KeyValuePair<int, string> pair in graphicStatistic.MethodHashDictionary)
            {
                //Console.WriteLine("{0}, {1}",
                //pair.Key,
                //pair.Value);
                sb.Append(pair.Key + " " + pair.Value);
                sb.AppendLine();
            }

            legendLabel.Content = sb.ToString();

            plotter.Viewport.FitToView();
        }

        /// <summary>
        /// Loads a data file and returns a list of Data objects.
        /// </summary>
        /// <param name="filename">The filename to load.</param>
        /// <returns>A list of Data objects.</returns>
        private List<Data> loadFile(string filename)
        {
            // Create list that contains all analysis objects
            List<Data> dataList = new List<Data>();

            // Read in every line in the file.
            using (StreamReader reader = new StreamReader(filename))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    // Do something with line
                    // Example of a typical line: 11:31:06;MobFox.Ads.AdProviders.0;1;A_0:39-F0-C1-EB-E8-5D-13-51-2C-40-3C-66-56-BB-D6-CA-CC-84-2A-D0;
                    // more complex example:
                    // 11:31:06;MobFox.Ads.AdProviders.0/0;0;A_2:20,A_1:0,A_0:F2-2C-03-ED-1A-82-6D-4D-8D-11-01-21-2D-8C-54-7F-2A-6E-8D-B8;
                    // So there are only up to 4 parts separated by ;

                    string[] parts = line.Split(';');
                    // Create a new Analysis object which holds all parsed information
                    Data analyisObject = new Data();
                    for (int i = 0; i < parts.Length; i++)
                    {
                        switch (i)
                        {
                            case 0:
                                // initializes with todays day in addition to the time
                                DateTime time = DateTime.Parse(parts[i]);
                                analyisObject.Time = time;
                                break;
                            case 1:
                                analyisObject.Type = parts[i];
                                break;
                            case 2:
                                analyisObject.MethodName = parts[i];
                                break;
                            case 3:
                                analyisObject.Variable = parts[i];
                                break;

                            default:
                                break;
                        }
                    }
                    dataList.Add(analyisObject);
                }
            }
            return dataList;
        }

        /// <summary>
        /// The method handler for saving a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SaveMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Save File Dialog
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Save statistics";
            sfd.ShowDialog();
            
        }

        /// <summary>
        /// The method handler for exiting the program.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ExitMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Exit the application and warn about unsaved data
            Application.Current.Shutdown();
        }

        /// <summary>
        /// The method handler for resizing the Window size of the application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // Set the Height and Width according to the surrounding tabControl
            RawDataGrid.Height = tabControl.ActualHeight - 50;
            RawDataGrid.Width = tabControl.ActualWidth - 10;
            RawDataGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
            MethodCountDataGrid.Height = tabControl.ActualHeight - 50;
            MethodCountDataGrid.Width = tabControl.ActualWidth - 10;
            MethodCountDataGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
            legenScrollViewer.Height = tabControl.ActualHeight - 50;
        }

        /// <summary>
        /// Clears all DataGrids, labels and the plotter for a newly opened file.
        /// </summary>
        private void clearData()
        {
            // clears the DataGrids
            RawDataGrid.Columns.Clear();
            MethodCountDataGrid.Columns.Clear();
            // resets the labels
            NumberMethodsLabel.Content = "Number of methods: ";
            NumberUniqueMethodsLabel.Content = "Number of unique methods: ";
            // resets the plotter
            // removes all data, but also the description for the axis :(
            //plotter.RemoveUserElements();
        }

        private void InstructionsMenuItem_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("See detailed instructions in the applications ReadMe.txt");
        }

        private void AboutMenuItem_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Copyright 2011, markus.rudel@rub.de");
        }
    }
}
